package com.ruoyi.system.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 电表工具类
 */
public class ElectricityMeterUtil {

    public static void main(String[] args) {
        System.out.println(InstructTypeConstant.getByKey("1").getValue());
        ElectricityMeterUtil u = new ElectricityMeterUtil();
        // 11 B6 00 01 01 02 A项电压
        // 43 C3   10 90
        //拉总闸 28 C0 00 00 00 00 34 12
        //合总闸 28 C0 00 00 00 00 78 56
        String a = u.dataAreaPlus33("50 CC 01 0D 09 04");
//        String a = "A0 17 00 99";
        System.out.println( a);
        String hexStr = "68 45 02 92 00 00 00 68 04 09 " + a +" 33 80 33";
//        String hexStr="68 45 02 92 00 00 00 68 01 02 F3 12F";
        //获取检验码
        String ten = u.getCSCheck(hexStr);
        System.out.println("校验码：" + ten);
        System.out.println("完整指令：FE FE " + hexStr +" "+ ten +" 16");
        String aa = u.getCompleteInstruct("45 02 92 00 00 00",InstructConstant.ELECTRICITY_METER_USED_INSTRUCT);
        System.out.println(aa);

        System.out.println(dataAreaPlus33("05 00"));
    }

    /**
     * 获取完整指令字符串
     * @param hexAddress 设备地址
     * @param constant 校验前的指令内容 InstructConstant类中获取
     * @return
     */
    public static String getCompleteInstruct(String hexAddress,String constant){
        String instructTxt = constant.replaceAll("FE","").trim();
        String addressInstaruct = MessageFormat.format(instructTxt,hexAddress);
        //获取校验码
        String ten = getCSCheck(addressInstaruct);
        return MessageFormat.format(constant,hexAddress)+" "+ten+" 16";
    }

    public static String getCompleteInstructSetUp(String hexAddress,String constant,String... data){
        String instructTxt = constant.replaceAll("FE","").trim();
        String[] param=null;
        if(data instanceof String[]) {
            int num = data.length;
            param = new String[num+1];
            for(int i=0; i<=num; i++){
                if(i==0) {
                    param[i] = hexAddress;
                } else {
                    param[i] = data[i-1];
                }
            }
        } else {
            param = new String[]{hexAddress};
        }
        String addressInstaruct = MessageFormat.format(instructTxt,param);

        //获取校验码
        String ten = getCSCheck(addressInstaruct);
        return MessageFormat.format(constant,param) +" "+ten+" 16";
    }
    /**
     * 数据域接收时减33
     * @param haxData
     * @return
     */
    public static String dataAreaSubtract33(String haxData){
        String resultStr = null;
        if(haxData != null) {
            //获取到单个数据数组
            String[] singles = haxData.split(" ");
            List<String> list = new ArrayList<>();
            for(int i=0; i<singles.length; i++) {
                list.add(makeCheckSubtract(singles[i]+" 33"));
            }
            resultStr = StringUtils.join(list," ");
        }
        return resultStr;
    }

    /**
     * 数据域发送时加33
     * @param haxData
     * @return
     */
    public static String dataAreaPlus33(String haxData){
        String resultStr = null;
        if(haxData!=null){
            //获取到单个数据数组
            String[] singles = haxData.split(" ");
            List<String> list = new ArrayList<>();
            for(int i=0; i<singles.length; i++){
                list.add(makeChecksum(singles[i]+" 33"));
            }
            resultStr = StringUtils.join(list," ");
        }
        return resultStr;
    }

    /**
     * 设备地址的转换
     * 转化前 45 02 92 00 00 00
     * 转换后 000000920245
     * @param deviceNo
     * @return
     */
    public static String addressConvertNo(String deviceNo,boolean isContinuityStr){
        String resultDeviceNo = null;
        if(deviceNo != null) {
            if(isContinuityStr)
            deviceNo = hexAddcharacter(deviceNo," ");
            String[] deviceNos = deviceNo.split(" ");
            LinkedList<String> items = new LinkedList<String>();
            for(int i=deviceNos.length; i>0; i--) {
                items.addLast(deviceNos[i-1]);
            }
            resultDeviceNo = StringUtils.join(items," ").replaceAll(" ","");
        }
        return resultDeviceNo;
    }
    /**
     * 设备地址的转换
     * 转化前 000000920245
     * 转换后 45 02 92 00 00 00
     * @param deviceNo
     * @return
     */
    public static String deviceAddressConvert(String deviceNo){
        String resultDeviceNo = null;
        if (deviceNo != null) {
            deviceNo = deviceNo.replace("", " ");
            int num = deviceNo.length()/4;
            LinkedList<String> items = new LinkedList<String>();
            String newStr;
            for(int i = 0; i < num; i++){
                newStr = "";
                newStr = deviceNo.substring(0, 4);
                deviceNo = deviceNo.substring(4);
                items.addFirst(newStr.replaceAll(" ", ""));
            }
            resultDeviceNo = StringUtils.join(items," ");
        }
        return resultDeviceNo;
    }
    /**
     * 获取指令中的校验码
     * @param hexStr
     * @return
     */
    public static String getCSCheck(String hexStr) {
        byte[] bytes = fromHexString(hexStr);
        int ck = 0;
        for(byte b : bytes){
            ck = ck+b;
        }
        //去除FE后，从帧起始符68H到数据域 全部字符的字节相加取模256，
        //保留一直字节，超过256会有多个字节所以要取模
        Integer a  = ck%0x100;
        System.out.println("检验码的和是："+ toHex(ck));
        String b = toHex(a);
        if(b.length() < 2) {
            b="0"+b;
        }
        if(b.length() > 2) {
            b= b.substring(b.length()-2);
        }
        return b;
    }

    /**
     * 转换为十六进制数据
     * @param num
     * @return
     */
    public static String toHex(int num) {
        char[] map = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        if (num == 0)
            return "0";
        String result = "";
        while (num != 0) {
            int x = num & 0xF;
            result = map[(x)] + result;
            num = (num >>> 4);
        }
        return result;
    }

    /**
     * 16进制数据转字节数组
     *
     * @param hexStr
     * @return
     */
    public static byte[] fromHexString(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        hexStr = hexStr.replaceAll(" ", "");
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * 将字节转换成16进制字符串
     * @param raw
     * @return
     */
    public static String getBufHexStr(byte[] raw) {
        String HEXES = "0123456789ABCDEF";
        if (raw == null) {
            return null;
        }
        final StringBuilder hex = new StringBuilder(2 * raw.length);
        for (final byte b : raw) {
            hex.append(HEXES.charAt((b & 0xF0) >> 4))
                    .append(HEXES.charAt((b & 0x0F)));
        }
        return hex.toString();
    }


    /**
     * 字符串转16进制
     *
     * @param str
     * @return
     */
    public static String stringToHex(String str) {
        char[] chars = str.toCharArray();
        StringBuilder sb = new StringBuilder(""); // String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组
        byte[] bs = str.getBytes();

        int bit;
        for (int i = 0; i < bs.length; i++) {
            bit = (bs[i] & 0x0f0) >> 4; // 高4位, 与操作 1111 0000
            sb.append(chars[bit]);
            bit = bs[i] & 0x0f; // 低四位, 与操作 0000 1111
            sb.append(chars[bit]);
        }
        return sb.toString().trim();
    }

    /**
     * 十六进制求差
     *
     * @param hexdata
     *            00 1E
     * @return
     */
    public static String makeCheckSubtract(String hexdata) {
        if (hexdata == null || hexdata.equals("")) {
            return "00";
        }
        hexdata = hexdata.replaceAll(" ", "");
        int total = 0;
        int len = hexdata.length();
        if (len % 2 != 0) {
            return "00";
        }
        int num = 0;
;
        while (num < len) {
            String s = hexdata.substring(num, num + 2);
            if(num==0){
                total += Integer.parseInt(s, 16);
            }else{
                total -= Integer.parseInt(s, 16);
            }
            num = num + 2;
        }
        return hexInt(total);
    }

    /**
     * 十六进制求和
     *
     * @param hexdata
     *            00 1E
     * @return
     */
    public static String makeChecksum(String hexdata) {
        if (hexdata == null || hexdata.equals("")) {
            return "00";
        }
        hexdata = hexdata.replaceAll(" ", "");
        int total = 0;
        int len = hexdata.length();
        if (len % 2 != 0) {
            return "00";
        }
        int num = 0;
        while (num < len) {
            String s = hexdata.substring(num, num + 2);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        return hexInt(total);
    }

    private static String hexIntSubtract(int total) {
        int a = total / 256;
        int b = total % 256;
        if (a > 255) {
            return hexInt(a) + format(b);
        }
        System.out.println("hex = " + a);

        return format(a) + format(b);
    }

    private static String hexInt(int total) {
        int a = total / 256;
        int b = total % 256;
        if (a > 255) {
            return hexInt(a) + format(b);
        }
        if(org.springframework.util.StringUtils.isEmpty(format(a) + format(b))){
            return "00";
        }
        return format(a) + format(b);
    }

    private static String format(int hex) {
        if(hex==0) return "";
        String hexa = Integer.toHexString(hex);
        int len = hexa.length();
        if (len < 2) {
            hexa = "0" + hexa;
        }

        return hexa.toUpperCase();
    }
    /**
     * 10进制转bcd
     * @param str 10进制数字 String.valueOf(int number);将10进制数字转成字符串传入此参数
     * @return bcd码
     */
    public static String DecimaltoBcd(String str){
        String b_num="";
        for (int i = 0; i < str.length(); i++) {

            String b = Integer.toBinaryString(Integer.parseInt(str.valueOf(str.charAt(i))));

            int b_len=4-b.length();

            for(int j=0;j<b_len;j++){
                b="0"+b;
            }
            b_num+=b;
        }

        return b_num;
    }
    /**
     * 16进制转bcd
     * 将16进制转成10进制，再将10进制转成bcd
     * @param hex 16进制数字String.valueOf(int number);这里忽略16进制的前缀0x，只转后面的数字为字符串类型，将16进制数字转成字符串传入此参数
     * @return bcd码
     */
    public static String HextoBcd(String hex){

        int decimal = Integer.parseInt(hex,16);

        String bcd = DecimaltoBcd(String.valueOf(decimal));

        return bcd;
    }

    /**
     * 给16进制的字符串添加指定字符
     * @param str
     * @return
     */
    public static String hexAddcharacter(String str,String character){
        char[] chars = str.toCharArray();
        StringBuffer sb = new StringBuffer();
        for(int i=0;i<chars.length;i++){
            if(i%2!=0){
                sb.append(chars[i-1]).append(chars[i]).append(character);
            }
        }
        return sb.toString().substring(0,sb.toString().lastIndexOf(character));
    }

    public static double BCDToDouble(byte[] sourceBytes, int precisionIndex)
    {
        StringBuffer sb = new StringBuffer();

        for (int index = 0; index < sourceBytes.length; index++)
        {
            sb.append(sourceBytes[index] >> 4 & 0xF);
            sb.append(sourceBytes[index] & 0xF);
            if (index == precisionIndex - 1) sb.append('.');
        }

        return Double.valueOf(sb.toString());
    }

    public static byte[] DecToBCDArray(long num) {
        int digits = 0;

        long temp = num;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }

        int byteLen = digits % 2 == 0 ? digits / 2 : (digits + 1) / 2;
        boolean isOdd = digits % 2 != 0;

        byte bcd[] = new byte[byteLen];

        for (int i = 0; i < digits; i++) {
            byte tmp = (byte) (num % 10);

            if (i == digits - 1 && isOdd)
                bcd[i / 2] = tmp;
            else if (i % 2 == 0)
                bcd[i / 2] = tmp;
            else {
                byte foo = (byte) (tmp << 4);
                bcd[i / 2] |= foo;
            }

            num /= 10;
        }

        for (int i = 0; i < byteLen / 2; i++) {
            byte tmp = bcd[i];
            bcd[i] = bcd[byteLen - i - 1];
            bcd[byteLen - i - 1] = tmp;
        }

        return bcd;
    }

    public static String addCharacterByLength(String str,Integer length,String character){
        Integer strLength = str.length();
        Integer subLength = length-strLength;
        if(subLength>0){
            for(int i=0;i<subLength;i++){
                str = character+str;
            }
        }
        return str;
    }

    public static int[] bytearray2intarray(byte[] barray)
    {
        int[] iarray = new int[barray.length];
        int i = 0;
        for (byte b : barray)
            iarray[i++] = b & 0xff;
        // "and" with 0xff since bytes are signed in java
        return iarray;
    }
}
